package com.spx.usercenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spx.usercenter.common.BaseResponse;
import com.spx.usercenter.common.ErrorCode;
import com.spx.usercenter.exception.BusinessException;
import com.spx.usercenter.model.domain.Team;
import com.spx.usercenter.mapper.TeamMapper;
import com.spx.usercenter.model.domain.User;
import com.spx.usercenter.model.domain.UserTeam;
import com.spx.usercenter.model.dto.TeamQuery;
import com.spx.usercenter.model.enums.TeamStatusEnum;
import com.spx.usercenter.model.request.TeamJoinRequest;
import com.spx.usercenter.model.request.TeamQuitRequest;
import com.spx.usercenter.model.request.TeamUpdateRequest;
import com.spx.usercenter.model.vo.TeamUserVO;
import com.spx.usercenter.model.vo.UserVO;
import com.spx.usercenter.service.TeamService;
import com.spx.usercenter.service.UserService;
import com.spx.usercenter.service.UserTeamService;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
* @author s
* @description 针对表【team(队伍)】的数据库操作Service实现
* @createDate 2024-03-15 18:40:04
*/
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
    implements TeamService {


    @Resource
    private UserTeamService userTeamService;

    @Resource
    private UserService userService;

    @Resource
    private TeamService teamService;

    @Resource
    private RedissonClient redissonClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addTeam(Team team, User loginUser){

        //1. 请求参数是否为空？
        if (team == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //2. 是否登录，未登录不允许创建
        if (loginUser == null){
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        //3. 校验信息
        final long userId = loginUser.getId();
        //   1. 队伍人数 > 1 且 <= 20
        int num = Optional.ofNullable(team.getMaxNum()).orElse(0);
        if (num < 1 || num > 20){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍人数不满足要求");
        }
        //   2. 队伍标题 <= 20
        String name = team.getName();
        if (StringUtils.isBlank(name) || name.length() > 20){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍标题不满足要求");
        }
        //   3. 描述 <= 512
        String description = team.getDescription();
        if (StringUtils.isNotBlank(description) && description.length() > 512){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍描述过长");
        }
        //   4. status 是否公开（int）不传默认为 0（公开）
        int status = Optional.ofNullable(team.getStatus()).orElse(0);
        TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(status);
        if (statusEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍状态不满足要求");
        }
        //   5. 如果 status 是加密状态，一定要有密码，且密码 <= 32
        String password = team.getPassword();
        if (TeamStatusEnum.SECRET.equals(statusEnum)) {
            if (StringUtils.isBlank(password) || password.length() > 32) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码设置不正确");
            }
        }
        //   6. 超时时间 > 当前时间
        Date expireTime = team.getExpireTime();
        if (new Date().after(expireTime)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "超时时间 > 当前时间");
        }
        //   7. 校验用户最多创建 5 个队伍
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId", userId);
        long hasTeamNum = this.count(queryWrapper);
        if (hasTeamNum >= 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户最多创建 5 个队伍");
        }
        //4. 插入队伍信息到队伍表
        team.setId(null);
        team.setUserId(userId);
        boolean result = save(team);
        Long teamId = team.getId();
        if (!result || teamId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "创建队伍失败");
        }
        //5. 插入用户  => 队伍关系到关系表
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(userId);
        userTeam.setTeamId(teamId);
        userTeam.setJoinTime(new Date());
        boolean save = userTeamService.save(userTeam);
        if (!result) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "创建队伍失败");
        }
        return teamId;


    }

    @Override
    public List<TeamUserVO> listTeam(TeamQuery teamQuery, boolean isAdmin) {
        QueryWrapper<Team> wrapper = new QueryWrapper<>();
        //组合查询条件
        //slelect * from team t join user_team ut on
        if (teamQuery != null){
            Long id = teamQuery.getId();
            if (id != null && id >= 0){
                wrapper.eq("id", id);
            }
            List<Long> idList = teamQuery.getIdList();
            if (idList != null){
                wrapper.in("id", idList);
            }
            String searchText = teamQuery.getSearchText();
            if (StringUtils.isNotBlank(searchText)){
                wrapper.and(wq -> wq.like("name", searchText).or().like("description",searchText));
            }
            String name = teamQuery.getName();
            if (StringUtils.isNotBlank(name)){
                wrapper.eq("name", name);
            }
            String description = teamQuery.getDescription();
            if (StringUtils.isNotBlank(description)){
                wrapper.like("description",description);
            }
            Integer maxNum = teamQuery.getMaxNum();
            if (maxNum != null && maxNum > 0){
                wrapper.eq("maxNum",maxNum);
            }
            Long userId = teamQuery.getUserId();
            if (userId != null && userId > 0){
                wrapper.eq("userId",userId);
            }
            Integer status = teamQuery.getStatus();
            TeamStatusEnum enumByValue = TeamStatusEnum.getEnumByValue(status);
            if (enumByValue == null){
                enumByValue = TeamStatusEnum.PUBLIC;
            }
            if (!isAdmin && enumByValue.equals(TeamStatusEnum.PRIVATE)){
                throw new BusinessException(ErrorCode.NOT_AUTH);
            }
            wrapper.eq("status",enumByValue.getValue());
        }
        //不展示已过期的队伍
        wrapper.and(qw -> qw.gt("expireTime",new Date())).or().isNull("expireTime");
        List<Team> teamList = this.list(wrapper);
        if (CollectionUtils.isEmpty(teamList)){
            return new ArrayList<>();
        }
        List<TeamUserVO>  teamUserVOList = new ArrayList<>();
        for (Team team : teamList) {
            Long userId = team.getUserId();
            if (userId == null){
                continue;
            }
            TeamUserVO teamUserVO = new TeamUserVO();
            BeanUtils.copyProperties(team,teamUserVO);
            User user = userService.getById(userId);
            if (user != null){
                UserVO userVO = new UserVO();
                BeanUtils.copyProperties(user,userVO);
                teamUserVO.setCreateUser(userVO);
            }
            teamUserVOList.add(teamUserVO);
        }
        return teamUserVOList;
    }

    /**
     * 更新队伍
     * @param teamUpdateRequest
     * @return
     */
    @Override
    public Boolean updateTeam(TeamUpdateRequest teamUpdateRequest,User loginUser) {
        if (teamUpdateRequest == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long id = teamUpdateRequest.getId();
        if (id == null || id < 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (this.getById(id) == null){
            throw new BusinessException(ErrorCode.NULL_ERROR,"队伍不存在");
        }
        Integer status = teamUpdateRequest.getStatus();
        if (TeamStatusEnum.getEnumByValue(status) == TeamStatusEnum.SECRET){
            if (StringUtils.isBlank(teamUpdateRequest.getPassword())){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"未设置密码");
            }
        }
        Team team = new Team();
        BeanUtils.copyProperties(teamUpdateRequest,team);
        if (loginUser.getId() != id && !userService.isAdmin(loginUser)){
            throw new BusinessException(ErrorCode.NOT_AUTH);
        }
        return this.updateById(team);
    }

    @Override
    public Boolean joinTeam(TeamJoinRequest teamJoinRequest, User loginUser) {


        Long teamId = teamJoinRequest.getTeamId();
        if (teamId == null || teamId <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //只能加入者未过期的队伍
        Team team = teamService.getById(teamId);
        if (team == null){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"队伍不存在");
        }
        Date expireTime = team.getExpireTime();
        if (expireTime != null && expireTime.before(new Date())){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"队伍已过期");
        }

        //禁止加入私有的队伍
        TeamStatusEnum enumByValue = TeamStatusEnum.getEnumByValue(team.getStatus());
        if (TeamStatusEnum.PRIVATE.equals(enumByValue)){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"禁止加入私有队伍");
        }
        //如果加入的队伍是加密的，必须密码匹配才可以
        String password = teamJoinRequest.getPassword();
        if (TeamStatusEnum.SECRET.equals(enumByValue)){
            if (StringUtils.isBlank(password) || !password.equals(team.getPassword())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");
            }
        }

        //只能加入未满的队伍
        long count = this.countTeamUserByTeamId(teamId);
        if (count >= team.getMaxNum()){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"队伍已满");
        }

        RLock lock = redissonClient.getLock("zsyn:join_team");

        try {
            while (true){
                if (lock.tryLock(0, 30000L, TimeUnit.MILLISECONDS)){
                    System.out.println("getLock: " + Thread.currentThread().getId());
                    //用户最多加入5个队伍
                    QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("userId",loginUser.getId());
                    count = userTeamService.count(queryWrapper);
                    if (count >= 5){
                        throw new BusinessException(ErrorCode.SYSTEM_ERROR,"最多加入5个队伍");
                    }
                    //不可以加入重复加入的队伍
                    queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("teamId",teamId);
                    queryWrapper.eq("userId",loginUser.getId());
                    count = userTeamService.count(queryWrapper);
                    if (count > 0){
                        throw new BusinessException(ErrorCode.SYSTEM_ERROR,"不能重复加入队伍");
                    }
                    //新增队伍 - 用户关联信息
                    UserTeam userTeam = new UserTeam();
                    userTeam.setUserId(loginUser.getId());
                    userTeam.setTeamId(teamId);
                    userTeam.setJoinTime(new Date());

                    boolean save = userTeamService.save(userTeam);
                    return save;

                }
            }

        } catch (InterruptedException e) {
            log.error("doCacheRecommendUser error", e);
            return false;
        } finally {
            //只能释放自己的锁
            if (lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }



    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean quitTeam(TeamQuitRequest teamQuitRequest, User loginUser) {
        if (teamQuitRequest == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        Long teamId = teamQuitRequest.getTeamId();
        if (teamId == null || teamId <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //校验队伍是否存在
        Team team = teamService.getById(teamId);
        if (team == null){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"队伍不存在");
        }
        //校验是否已经加入队伍
        long userId = loginUser.getId();
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userid",userId);
        queryWrapper.eq("teamId",teamId);
        long count = userTeamService.count(queryWrapper);
        if (count == 0){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"未加入队伍");
        }
        count = this.countTeamUserByTeamId(teamId);
        //如果队伍只有一个人
        if (count == 1){
            //解散队伍
            teamService.removeById(teamId);
        }else {
            //如果是队长
            if (team.getUserId() == userId){
                QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
                userTeamQueryWrapper.last("order by id asc limit 2");
                List<UserTeam> userTeamList = userTeamService.list(userTeamQueryWrapper);
                if (CollectionUtils.isEmpty(userTeamList) || userTeamList.size() <= 1){
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR);
                }
                UserTeam nextUserTeam = userTeamList.get(1);
                Team updateTeam = new Team();
                updateTeam.setId(teamId);
                updateTeam.setUserId(nextUserTeam.getId());
                boolean result = this.updateById(updateTeam);
                if (!result) {
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "更新队伍队长失败");
                }
            }
        }

        return userTeamService.remove(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteTeam(long id, User loginUser) {

        //校验队伍是否存在
        Team team = teamService.getById(id);
        if (team == null){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"队伍不存在");
        }
        //检验是不是队长
        if (team.getUserId() != loginUser.getId()){
            throw new BusinessException(ErrorCode.NOT_AUTH,"无权限操作");
        }
        //移除所有加入队伍的关联信息
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("teamId",id);
        boolean result = userTeamService.remove(queryWrapper);
        if (!result){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"删除关联队伍信息失败");
        }

        return teamService.removeById(id);
    }

    /**
     * 获取某队伍当前人数
     *
     * @param teamId
     * @return
     */
    private long countTeamUserByTeamId(long teamId) {
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("teamId", teamId);
        return userTeamService.count(userTeamQueryWrapper);
    }

}




